#include "cam_opencv.h"

my_opencv::my_opencv(QString cameraLocation, Board board)      //class init
{
    webcamName = cameraLocation.toStdString();
    connectionAttempts = 0;
    inputOpenCV = cameraInput;

    setupCamera();

    if (usingMipi)
    {
        if (board == G2L) cameraInitialization = G2L_CAM_INIT;
    }

    connectCamera();
}

void my_opencv::setupCamera()
{
    struct v4l2_capability cap;
    int fd = open(webcamName.c_str(), O_RDONLY);

    if (fd == -1)
        qWarning() << "Could not open file:" << webcamName.c_str();

    if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1)
    {
        qWarning("Could not retrieve v4l2 camera information");
        webcamInitialised = false;
    } else {
        webcamInitialised = true;

        std::string busInfo = std::string((char*)cap.bus_info);

        if (busInfo.find("platform") != std::string::npos) {
            usingMipi = true;
        } else if (busInfo.find("usb") != std::string::npos) {
            usingMipi = false;
        } else {
            qWarning("Camera format error, defaulting to MIPI");
            usingMipi = true;
        }
    }
    close(fd);
}

void my_opencv::connectCamera()
{
    connectionAttempts++;
    int cameraWidth = 800;
    int cameraHeight = 600;

    if (usingMipi) {
        std::string stdoutput;
        /* Run media-ctl command */
        if (runCommand(cameraInitialization, stdoutput))
            qWarning("Cannot initialize the camera");
    }

    /* Define the format for the camera to use */
    camera = new cv::VideoCapture(webcamName, cv::CAP_V4L2);
    camera->set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('U', 'Y', 'V', 'Y'));
    camera->open(webcamName);

    if (!camera->isOpened()) {
        qWarning("Cannot open the camera");
        webcamOpened = false;
    } else {
        webcamOpened = true;
    }

    if (!usingMipi) {
        camera->set(cv::CAP_PROP_FPS, 20);
        camera->set(cv::CAP_PROP_BUFFERSIZE, 1);
        cameraWidth = 640;
        cameraHeight = 480;
    }

    camera->set(cv::CAP_PROP_FRAME_WIDTH, cameraWidth);
    camera->set(cv::CAP_PROP_FRAME_HEIGHT, cameraHeight);

    checkCamera();
}

int my_opencv::runCommand(std::string command, std::string &stdoutput)
{
    size_t charsRead;
    int status;
    char buffer[512];

    FILE *output = popen(command.c_str(), "r");

    if (output == NULL)
        qWarning("cannot execute command");

    stdoutput = "";
    while (true) {
        charsRead = fread(buffer, sizeof(char), sizeof(buffer), output);

        if (charsRead > 0)
            stdoutput += std::string(buffer, charsRead);

        if (ferror(output)) {
            pclose(output);
            qWarning("Could not retreive output from command");
        }

        if (feof(output))
            break;
    }

    status = pclose(output);
    if (status == -1)
        qWarning("Could not terminate from command");

    return WEXITSTATUS(status);
}

void my_opencv::checkCamera()
{
    /* Check to see if camera can retrieve a frame*/
    *camera >> picture;

    if (picture.empty()) {
        qWarning("Lost connection to camera, reconnecting");
        camera->release();

        if (connectionAttempts < 3) {
            connectCamera();
        } else {
            qWarning() << "Could not retrieve a frame, attempts: " << connectionAttempts;
            webcamInitialised = false;
        }
    }
}

void my_opencv::my_drawing(Mat& image)
{
    //绘制矩形
    //rectangle(image, Point(200, 200), Point(300, 300), Scalar(125, 125, 125), -1);//-1为填充
    rectangle(image,Rect(400,450,100,150), Scalar(0, 125, 125), 2);//2为线宽，不填充

    Mat bg = Mat::zeros(image.size(), image.type());
    rectangle(bg, Point(200, 200), Point(300, 300), Scalar(0, 0, 255), -1);
    Mat dst;
    addWeighted(image, 0.7, bg, 0.3, 0, dst);
    //绘制圆
    circle(image, Point(100, 100), 50, Scalar(255, 255, 255), 3);
    //绘制直线
    line(image, Point(50, 50), Point(50, 200),Scalar(255,0,0), 2, LINE_4, 0);
    //绘制椭圆
    //这里的RotatedRect参数表示，中心点，长轴短轴，旋转角度
    ellipse(image, RotatedRect(Point2f(300, 300), Size2f(200, 100), 0), Scalar(0, 255, 255), 2);
}

void my_opencv::my_resize(Mat& image)
{
    Mat zoomin, zoomout;
    int h = image.rows;
    int w = image.cols;
    resize(image, zoomin,Size(w/2,h/2),0,0,INTER_LINEAR);
    resize(image, zoomout, Size(w*1.2, h*1.2), 0, 0, INTER_LINEAR);
}

my_opencv::~my_opencv()
{
    camera->release();
}

bool my_opencv::cameraInit()
{
    return webcamInitialised;
}

bool my_opencv::getCameraOpen()
{
    return  webcamOpened;
}

/*important function*/
cv::Mat* my_opencv::getImage(unsigned int iterations)
{
    /* For camera input, grab the latest frame from the camera */
    do {
        *camera >> picture;

        if (picture.empty()) {
            qWarning("Image retrieval error");
            return nullptr;
        }

    } while (--iterations);
    cv::cvtColor(picture, picture, cv::COLOR_BGR2RGB);

    return &picture;
}
